#include "ltcs_fs.h"

void* ltcs_trusted_start(struct seq_file* m, loff_t* pos)
{
    struct trusted_elf_entry* entry;
    rcu_read_lock();
    entry = ltcs_list_del_entry();
    if (!entry) {
        rcu_read_unlock();
        return NULL;
    }
    rcu_read_unlock();
    return entry;
}

void* ltcs_trusted_next(struct seq_file* m, void* v, loff_t* pos)
{
    struct trusted_elf_entry* entry = v;
    rcu_read_lock();
    entry = ltcs_list_del_entry();
    rcu_read_unlock();
    (*pos)++;
    return entry;
}

void ltcs_trusted_stop(struct seq_file* m, void* v) { return; }

int ltcs_trusted_show(struct seq_file* m, void* v)
{
    struct trusted_elf_entry* entry = v;
    rcu_read_lock();
    seq_printf(m, "%s\n", entry->file_name);
    ltcs_list_free_entry(entry);
    rcu_read_unlock();
    return 0;
}

int ltcs_trusted_open(struct inode* inode, struct file* file)
{
    return seq_open(file, &ltcs_trusted_seqops);
}

ssize_t ltcs_trusted_read(struct file* file, char __user* ubuf, size_t count,
                          loff_t* ppos)
{
    ssize_t                   ret = 0;
    struct trusted_elf_entry* entry;
    if (*ppos > 0) return ret;

    entry = ltcs_list_del_entry();
    if (!entry) return ret;
    ret = sprintf(ubuf, "%s", entry->file_name);
    ltcs_list_free_entry(entry);

#ifdef DEBUG
    ltcs_list_print_list();
#endif
    *ppos += ret;
    return ret;
}

ssize_t ltcs_trusted_write(struct file* file, const char __user* ubuf,
                           size_t count, loff_t* ppos)
{
    struct trusted_elf_entry* entry;
    char*                     store_buf;
    if (count <= 0) return -EINVAL;

    entry = kzalloc(sizeof(struct trusted_elf_entry), GFP_KERNEL);
    if (!entry) {
        debug_info("alloc memery for trusted_elf_entry failed.\n");
        return count;
    }
    store_buf = kzalloc(count, GFP_KERNEL);
    if (!store_buf) {
        debug_info("alloc memery for store_buf failed.\n");
        kfree(entry);
        return count;
    }

    strncpy(store_buf, ubuf, count);
    entry->file_name = store_buf;
    ltcs_list_add_entry(entry);
#ifdef DEBUG
    ltcs_list_print_list();
#endif
    return count;
}

static int ltcs_sysfs_init(void)
{
    ltcs_dir = securityfs_create_dir(LTCS_TRUSTED_DIR, NULL);
    if (IS_ERR(ltcs_dir)) {
        debug_info("%s create failed.\n", LTCS_TRUSTED_DIR);
        return 1;
    }
    ltcs_trusted_file = securityfs_create_file(LTCS_TRUSTED_FILE, 0600,
                                               ltcs_dir, NULL, &ltcs_fops);
    if (IS_ERR(ltcs_trusted_file)) {
        securityfs_remove(ltcs_dir);
        debug_info("create %s failed.\n", LTCS_TRUSTED_FILE);
        return 1;
    }
    debug_info("ltcs fs init\n");
    return 0;
}

static void ltcs_sysfs_free(void)
{
    securityfs_remove(ltcs_trusted_file);
    securityfs_remove(ltcs_dir);
    debug_info("ltcs fs free\n");
    return;
}